#include "Game.h"
#include <iostream>
#include "PrimitiveShapes.h"
#include "TextureLoader.h"
#include "CameraManager.h"
using namespace std;

#ifndef M_PI
#define M_PI 3.1415926535
#endif

GLuint texId;
std::vector<btRigidBody*> bodies;
GLUquadricObj* quad;

void Game::renderSphere(btRigidBody* b)
{
	if(b->getCollisionShape()->getShapeType()!=SPHERE_SHAPE_PROXYTYPE)
		return;
	glColor3f(1,0,0);
	glPushMatrix();
		float r=((btSphereShape*)b->getCollisionShape())->getRadius();
		btVector3 vec;
		float tmp;
		btTransform t;
		b->getMotionState()->getWorldTransform(t);
		vec=t.getOrigin();
		glTranslatef(vec.x(),vec.y(),vec.z());
		gluSphere(quad,r,20,20);
	glPopMatrix();
}

btRigidBody* Game::createSphere(float rad,float x,float y,float z,float mass)
{
	btTransform transform;
	transform.setIdentity();
	transform.setOrigin(btVector3(x,y,z));
	btDefaultMotionState* motionState=new btDefaultMotionState(transform);
	btSphereShape* sphereShape=new btSphereShape(rad);
	btVector3 inertia(0,0,0);
	if(mass!=0)
		sphereShape->calculateLocalInertia(mass,inertia);
	btRigidBody::btRigidBodyConstructionInfo info(mass,motionState,sphereShape,inertia);
	btRigidBody* body=new btRigidBody(info);
	pWorld->addRigidBody(body);
	bodies.push_back(body);
	return body;
}

Game::Game(int w, int h)
{
	SDL_Init( SDL_INIT_EVERYTHING );
	screen = SDL_SetVideoMode(w, h, 32, SDL_SWSURFACE | SDL_OPENGL);

	init();

	glTerrain = new Terrain("terrain/heightmap.bmp", 5, 15, 5);

	config = new btDefaultCollisionConfiguration();
	dispatcher = new btCollisionDispatcher(config);
	pairCache = new btDbvtBroadphase();
	solver=new btSequentialImpulseConstraintSolver();
	pWorld = new btDiscreteDynamicsWorld(dispatcher, pairCache, solver, config);

	pWorld->setGravity(btVector3(0.0, -9.81f, 0.0));

	terrain = new btHeightfieldTerrainShape(glTerrain->width,glTerrain->length,
		glTerrain->data(), 15.0, 0.0, 15.0, 1, PHY_FLOAT, true);
	terrain->setLocalScaling(btVector3(2, 10, 2));

	btTransform t;
	t.setIdentity();
	//t.setOrigin(btVector3(0,-15,0));
	btMotionState* motion = new btDefaultMotionState(t);
	btRigidBody::btRigidBodyConstructionInfo info(0.0,motion,terrain);
	btRigidBody* body = new btRigidBody(info);
	pWorld->addRigidBody(body);
	bodies.push_back(body);

	quad=gluNewQuadric();

	running = true;
	cam.rotate(10, Vector3(1, 0, 0));
	cam.translate(Vector3(0, 0, 5));

	CameraManager::instance()->setCamera(&cam);

	angle = 0.0f;

	texId = TextureLoader::instance()->loadTexture("text.png");

	box.load("box/box.obj", "box/box_texture.png");
	floor.load("floor/floor.obj","floor/floor.png");
	banner.load("banner/banner.obj", "banner/banner.png");

	e = new Box("box/box.obj", "box/box_texture.png");
}

Game::~Game(void)
{
}

void Game::render()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();

	angle += 1.f;
	if (angle > 360.f)
		angle -= 360.f;

	cam.updateRotation();
	cam.draw();

	glPushMatrix();
	glTranslatef(0, -20, 0);
	glTerrain->render();
	glPopMatrix();
    
    glPushMatrix();
    Matrix4 mdGrid;
    mdGrid.identity();
	mdGrid.translate(0, -1.f, 0);
    glMultMatrixf(mdGrid.getTranspose());
	floor.render();
    glPopMatrix();
	
    glPushMatrix();
    Matrix4 mdBox;
    mdBox.identity();
	mdBox.rotateY(angle);
    glMultMatrixf(mdBox.getTranspose());
	box.render();
    glPopMatrix();
	
	glPushMatrix();
    Matrix4 mdQuad;
    mdQuad.identity();
	mdQuad.rotateX(-90.f);
	mdQuad.rotateY(180.f);
	mdQuad.translate(0, 2, -15);
    glMultMatrixf(mdQuad.getTranspose());
	banner.render();
	glPopMatrix();

	e->draw();

	for(int i=0;i<bodies.size();i++)
	{
		if(bodies[i]->getCollisionShape()->getShapeType()==SPHERE_SHAPE_PROXYTYPE)
			renderSphere(bodies[i]);
	}
}

void Game::init()
{
	glClearColor(0.0, 0.0, 0.0, 1.0);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45, 640.0/480.0, 1.0, 500.0);
	glMatrixMode(GL_MODELVIEW);
	glEnable(GL_DEPTH_TEST);
}

void Game::draw()
{
	btRigidBody* sphere;
	while (running)
	{
		start = SDL_GetTicks();
		while (SDL_PollEvent(&evt))
		{
			switch(evt.type)
			{
			case SDL_QUIT:
				running = false;
				break;
			case SDL_KEYDOWN:
				if (evt.key.keysym.sym == SDLK_ESCAPE) {
					running = false;
				}
				else if (evt.key.keysym.sym == SDLK_SPACE) {
					sphere = createSphere(1.0, 0, 20, 0, 10.0);
					Vector3 dir = cam.getForwardVector().normalize() * 10;
					sphere->setLinearVelocity(btVector3(dir.x,dir.y,dir.z));
				}
				break;
			}
		}
		pWorld->stepSimulation(1/60.0f);
		render();
		SDL_GL_SwapBuffers();

		if (1000/30 > (SDL_GetTicks() - start))
			SDL_Delay(1000/30 - (SDL_GetTicks() - start));
	}

	SDL_Quit();
}
